package org.hit.burkun.network.models;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;

import org.hit.burkun.entities.Entity;
import org.hit.burkun.file.FileHelper;
import org.hit.burkun.network.EdgeInfo;
import org.hit.burkun.network.GraphFeatures;
import org.hit.burkun.network.SerializableGraph;
import org.hit.burkun.network.Vertex;
import org.hit.burkun.network.models.SimplePageRank.PangeRankOutPut;
import org.hit.burkun.network.models.SimplePageRank.VertexWithPr;
import org.hit.burkun.network.tester.ValidData;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class BiographMethods {

	private static Logger log = LoggerFactory.getLogger(BiographMethods.class);
	
	public static void main(String[] args) {
//		SerializableGraph sg = StaticMethods.getSimpleGraph3();
//		//sg.getVertexByUmls("A");
//		RandomWalkWithRestart rr = new RandomWalkWithRestart(sg, sg.getVertexByUmls("A"));
//		rr.initMatrix(true);
	}

	public static LinkedList<String> doBioGraphMethod(String cui, HashMap<Vertex, Double> resG, SerializableGraph sg, boolean useWeight, double zuni){
		HashSet<EdgeInfo> vaildData = ValidData.splitVaildData(sg, cui);
		double eps = 1e-12;
		LinkedList<String> res = new LinkedList<>();
		for(EdgeInfo v : vaildData){
			GraphFeatures.removeEdgeFromNetWork(sg, cui, v);
			log.debug("current gene:" + v);
			LinkedList<VertexWithPr> pres = getFinalPrByUmls(cui, resG, sg, zuni, useWeight, eps);
			double tops = writeFile(pres, cui+"-wight-"+useWeight+"-"+v.getVertex().getDbids(), Entity.TYPE.GENE_ID, v.getVertex());
			res.add(cui + "$" + v.getVertex().getDbids() + "$" + tops);
			//reverse
			GraphFeatures.addEdgeToNetWork(sg, cui, v, true);
		}
		if(useWeight){
			FileHelper.writeFile("data/ranking/weight/" + cui + "-wight-"+useWeight+"-zuni-"+zuni+".txt", res);
		}else{
			FileHelper.writeFile("data/ranking/noweight/" + cui + "-wight-"+useWeight+"-zuni-"+zuni+".txt", res);
		}
		return res;
	}

	
	public static double writeFile(LinkedList<VertexWithPr> pr, String fileName, Entity.TYPE filterType, Vertex tv){
		ArrayList<PangeRankOutPut> res = new ArrayList<PangeRankOutPut>();
		for (VertexWithPr v : pr) {
			if(v.getVertex().getNodeType().equals(filterType.getTag())){
				BigDecimal bigDecimal = new BigDecimal(v.getPr());
				PangeRankOutPut pro = new PangeRankOutPut();
				pro.setCui(v.getVertex().getUmlsId());
				pro.setPr(bigDecimal);
				pro.setDbid(v.getVertex().getDbids());
				res.add(pro);
			}
		}
		Collections.sort(res);
		Collections.reverse(res);
		int counter = 0;
		double finalRanker = 0;
		for(PangeRankOutPut po : res){
			counter ++;
			if(po.getCui().equals(tv.getUmlsId())){
				finalRanker = counter;
			}
		}
		double tops = finalRanker/res.size();
		FileHelper.writeFile("data/ranking/raw/"+ fileName +"-" + tops +".txt", res);
		return tops;
	}
	
	
	public static LinkedList<VertexWithPr> getFinalPrByUmls(String uid, HashMap<Vertex, Double> gmapRes, SerializableGraph sg, double restartZuni, boolean useWeight, double eps){
			LinkedList<VertexWithPr> pres = getRadomWalkWithRestart(uid, sg, useWeight,restartZuni, eps);
			for(VertexWithPr vp : pres){
				vp.setPr(vp.getPr() / (Math.sqrt(gmapRes.get(vp.getVertex()))+eps));
			}
			return pres;
	}
	
	private static LinkedList<VertexWithPr> getRadomWalkWithRestart(String uid, SerializableGraph sg, boolean useWeight, double zuni, double eps){
		Vertex v = sg.getVertexByUmls(uid);
		RandomWalkWithRestart spr =new RandomWalkWithRestart(sg, v);
		spr.setZuni(zuni);
		return spr.getPageRank(useWeight, 100, eps);
	}
	
	public static HashMap<Vertex, Double> getGlobalPr(boolean useWeight, SerializableGraph sg, double zuni, double eps){
		SimplePageRank spr =new SimplePageRank(sg);
		spr.setZuni(zuni);
		//global pr
		LinkedList<VertexWithPr> gres = spr.getPageRank(useWeight, 2000, eps);
		HashMap<Vertex, Double> gmapRes = new HashMap<>();
		for(VertexWithPr vp : gres){
			gmapRes.put(vp.getVertex(), vp.getPr());
		}
		return gmapRes;
	}

}
